package se.webbzon.oschi01.worldarea;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;

import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Node;
import javax.media.j3d.WakeupOnElapsedTime;
import javax.vecmath.Point3d;

import se.webbzon.boltzmann.debug.Debug;

public class WorldEngineTimer {
	
	// A list of all world engines attached to this timer
	private final Collection<WorldEngine> engines;

	// The time in milliseconds between execution of two global steps 
	// (approximately)
	private final long millis;
		
	// Whatever the world is paused or not
	private volatile boolean paused;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new WorldEngineTimer which executes a global step
	 * for all engines attached to this timer every 30ms (approximately). **/
	public WorldEngineTimer() {
		this(30);
	}
	
	public WorldEngineTimer(long millis) {
		this.millis = millis;
		engines = new ArrayList<WorldEngine>();
		Timer timer = new Timer();
		timer.schedule(new TimerTaskImpl(), 0, millis);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Attaches an engine to this world engine timer. **/
	public boolean attachEngine(WorldEngine engine) {
		int d;
		Debug.debugCollection(this, engines);
		return engines.add(engine);
	}
	
	/** Detaches an engine from this world engine timer. **/
	public boolean detachWorld(WorldArea world) {
		return engines.remove(world);
	}
	
	/** Pauses the execution of this world engine timer. **/
	public void setPaused(boolean paused) {
		this.paused = paused;
	}
	
	/** Returns true if the world engine timer is paused. **/
	public boolean getPaused() {
		return paused;
	}
	
	/** Returns a new java3d node associated with this instance. This method
	 * should only be used by by the WorldAreaViewFactory upon creation. **/
	public Node makeNode() {
		BranchGroup branchGroup = new BranchGroup();
		//branchGroup.addChild(new BehaviorImpl());
		branchGroup.compile();
		return branchGroup; 
	}
	
	private final class TimerTaskImpl extends TimerTask {

		@Override
		public void run() {
			if (!paused) synchronized (engines) {
				for (WorldEngine engine : engines)
					engine.performStep();
			}
		}
		
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class BehaviorImpl extends Behavior {
		
		/*============================================================
		Constructors
		============================================================*/
		
		public BehaviorImpl() {
			setSchedulingBounds(new BoundingSphere(new Point3d(),Double.MAX_VALUE));
		}
		
		/*============================================================
		Public Methods
		============================================================*/

		@Override public void initialize() {
			this.wakeupOn(new WakeupOnElapsedTime(millis));
		}

		@SuppressWarnings("rawtypes")
		@Override public void processStimulus(Enumeration cirtera) {
			if (!paused) synchronized (engines) {
				for (WorldEngine engine : engines)
					engine.performStep();
			}
			
			this.wakeupOn(new WakeupOnElapsedTime(millis));
		}
		
	}

}
